package com.netease.nie.facade;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.netease.nie.base.cache.CacheParam;
import com.netease.nie.base.cache.DataOperation;
import com.netease.nie.base.cache.redis.RedisManager;
import com.netease.nie.base.exceptions.BusinessException;
import com.netease.nie.base.machine.MachineConfig;
import com.netease.nie.base.threadpool.SingleExecutorTask;
import com.netease.nie.base.utils.CopyUtils;
import com.netease.nie.base.utils.CustomDateFormatUtils;
import com.netease.nie.base.utils.DateUtils;
import com.netease.nie.config.AdminAreaProperties;
import com.netease.nie.config.CreditGradeProperties;
import com.netease.nie.constants.BusinessConstants;
import com.netease.nie.constants.CachePrefixConstants;
import com.netease.nie.constants.CreditHistoryChangeStants;
import com.netease.nie.constants.CreditHistoryOriginStants;
import com.netease.nie.constants.CustomGoodsConstants;
import com.netease.nie.constants.ExchangeDealStatusConstatns;
import com.netease.nie.constants.GoodsTypeStants;
import com.netease.nie.constants.OrdersStatusConstants;
import com.netease.nie.dto.AddressDto;
import com.netease.nie.dto.ExchangeGoodsConfigDto;
import com.netease.nie.dto.GoodsExchangeParamDto;
import com.netease.nie.dto.GoodsExchangeRequestDto;
import com.netease.nie.dto.GoodsExchangeResponseDto;
import com.netease.nie.dto.GoodsRobParamDto;
import com.netease.nie.dto.OrdersAddressDto;
import com.netease.nie.dto.OrdersLogDto;
import com.netease.nie.dto.OrdersTraceDto;
import com.netease.nie.model.Credit;
import com.netease.nie.model.CreditHistory;
import com.netease.nie.model.GoodsExchangeRecord;
import com.netease.nie.model.Orders;
import com.netease.nie.service.AddressService;
import com.netease.nie.service.CreditService;
import com.netease.nie.service.ExchangeGoodsConfigService;
import com.netease.nie.service.GoodsExchangeRecordService;
import com.netease.nie.service.GoodsExchangeService;
import com.netease.nie.service.OrdersAddressService;

/**
 * 商品兑换
 * @author wwbn3695
 * @createDate July 14th,2016
 *
 */
@Service
public class GoodsExchangeFacadeImpl implements GoodsExchangeFacade {
	
	private static Logger goodsExchangeLogger = Logger.getLogger("kh.goods-exchange");
	
	private static final String GOODS_CONFIG_PREFIX = CachePrefixConstants.GoodsPrefix.GOODS_CONFIG_PREFIX;
	
	private static final String GOODS_STOCK_PREFIX = CachePrefixConstants.GoodsPrefix.GOODS_STOCK_PREFIX;
	
	private static final String EXCHANGE_CODE_LIST_PREFIX = CachePrefixConstants.GoodsPrefix.GOODS_EXCHANGE_CODE_LIST_PREFIX;
	
	private static final String TOTAL_BUYING_COUNT = CachePrefixConstants.BuyingPrefix.TOTAL_BUYING_COUNT;
	
	private static final String CURRENT_DATE_BUYING_COUNT = CachePrefixConstants.BuyingPrefix.CURRENT_DATE_BUYING_COUNT;
	
	private static final String GOODS_SERIAL_PREFIX = CachePrefixConstants.GoodsPrefix.GOODS_SERIAL_PREFIX;
	
	private static final String EXCHANGED_LIST_PREFIX = CachePrefixConstants.GoodsPrefix.EXCHANGED_LIST_PREFIX;
	
	private static final String USER_CREDIT_PREFIX = CachePrefixConstants.UserPrefix.USER_CREDIT_PREFIX;
	
	@Autowired
	private ExchangeGoodsConfigService exchangeGoodsConfigService;
	
	@Autowired
	private GoodsExchangeService goodsExchangeService;
	
	@Autowired
	private CreditService creditService;
	
	@Autowired
	private AddressService addressService;
	
	@Autowired
	private OrdersAddressService ordersAddressService;
	
	@Autowired
	private AdminAreaProperties adminAreaProperties;
	
	@Autowired
	private GoodsExchangeRecordService goodsExchangeRecordService;
	
	@Autowired
	private MachineConfig machineConfig;
	
	@Autowired
	private CreditGradeProperties creditGradeProperties;
	
	public GoodsExchangeResponseDto goodsExchange(long userId, GoodsExchangeRequestDto goodsExchangeRequestDto) {
		final int goodsId = goodsExchangeRequestDto.getGoodsId();
		ExchangeGoodsConfigDto exchangeGoodsConfigDto = queryExchangeGoodsConfigDtoById(goodsId);
		if (exchangeGoodsConfigDto == null)
			return null;
		
		validate(userId, exchangeGoodsConfigDto);
		//扣除当前库存
		int stock = deductGoodsStock(goodsId);
		boolean exchangeStatus = false;
		Orders orders = null;
		GoodsExchangeResponseDto goodsExchangeResponseDto = new GoodsExchangeResponseDto();
		if (stock >= 0) {
			try {
				Credit credit = creditService.queryUserCreditByUserId(userId);
				validateUserCurrentCredit(credit, exchangeGoodsConfigDto);
			} catch (Exception e) {
				raiseGoodsStock(goodsId);
				throw new BusinessException(BusinessConstants.CREDIT_NOT_ENOUGH.getCode(), "您的奇遇点不足");
			}
			
			SingleExecutorTask singleExecutorTask = SingleExecutorTask.getInstance();
			GoodsExchangeParamDto goodsExchangeParamDto = new GoodsExchangeParamDto();
			goodsExchangeParamDto.setExchangeGoodsConfigDto(exchangeGoodsConfigDto);
			int goodsType = exchangeGoodsConfigDto.getGoodsType();
			int abstractId = exchangeGoodsConfigDto.getGoodsId();

			Credit credit = new Credit();
			credit.setUserId(userId);
			credit.setReadyToExpireCredit(exchangeGoodsConfigDto.getPrice());
			credit.setCurrentCredit(exchangeGoodsConfigDto.getPrice());
			credit.setTotalUseCredit(exchangeGoodsConfigDto.getPrice());
			goodsExchangeParamDto.setCredit(credit);
			
			CreditHistory creditHistory = generateCreditHistory(userId, exchangeGoodsConfigDto);
			goodsExchangeParamDto.setCreditHistory(creditHistory);
			
			Long orderId = null;
			int uniqueNumber = uniqueNumber(goodsId);
			goodsExchangeParamDto.setUniqueNumber(uniqueNumber);
			if (goodsType == GoodsTypeStants.REDEEM_CODE.getCode()) {
				//兑换类型为兑换码,兑换码的缓存是由抽象商品统一管理
				String exchangeCode = getExchangeCode(abstractId);
				if (StringUtils.isBlank(exchangeCode))
					throw new BusinessException(BusinessConstants.EXCHANGE_CODE_NOT_EXISTS.getCode(), "商品兑换码不存在");
				int exchangeCodeId = Integer.valueOf(exchangeCode);
				orders = generateOrder(userId, goodsExchangeParamDto, exchangeCodeId);
				try {
					orderId = goodsExchangeService.updateGoodsExchangeStatus(orders, goodsExchangeParamDto);
					exchangeStatus = true;
					//日志记录
					SaveGoodsExchangeLogWorker goodsExchangeLogWorker = new SaveGoodsExchangeLogWorker(orders, exchangeStatus);
					singleExecutorTask.executer(goodsExchangeLogWorker);
				} catch (Exception e) {
					//兑换失败,释放库存
					raiseGoodsStock(goodsId);
					//兑换码的缓存是由抽象商品统一管理
					raiseExchangeCode(abstractId, exchangeCode);
				}
			} else if (goodsType == GoodsTypeStants.E_CREDENTIAL.getCode()) {
				//兑换类型为电子凭证
				orders = generateOrder(userId, goodsExchangeParamDto);
				try {
					orderId = goodsExchangeService.updateGoodsExchangeStatus(orders, goodsExchangeParamDto);
					exchangeStatus = true;
					//日志记录
					SaveGoodsExchangeLogWorker goodsExchangeLogWorker = new SaveGoodsExchangeLogWorker(orders, exchangeStatus);
					singleExecutorTask.executer(goodsExchangeLogWorker);
				} catch (Exception e) {
					//兑换失败,释放库存
					raiseGoodsStock(goodsId);
				}
			} else if (goodsType == GoodsTypeStants.PRIVILEGE_PURCHASE_RIGHT.getCode()) {
				//兑换类型为特权购买资格
				orders = generateOrder(userId, goodsExchangeParamDto);
				try {
					orderId = goodsExchangeService.updateGoodsExchangeStatus(orders, goodsExchangeParamDto);
					exchangeStatus = true;
					//解锁商品待实现
					//日志记录
					SaveGoodsExchangeLogWorker goodsExchangeLogWorker = new SaveGoodsExchangeLogWorker(orders, exchangeStatus);
					singleExecutorTask.executer(goodsExchangeLogWorker);
				} catch (Exception e) {
					//兑换失败,释放库存
					raiseGoodsStock(goodsId);
				}
			} else if (goodsType == GoodsTypeStants.ENTITY.getCode()) {
				//兑换类型为实物商品
				try {
					OrdersAddressDto ordersAddressDto = getAddressDto(goodsExchangeRequestDto.getAddressId(), userId);
					
					goodsExchangeParamDto.setOrdersAddressDto(ordersAddressDto);
					OrdersTraceDto ordersTraceDto = new OrdersTraceDto();				
					goodsExchangeParamDto.setOrdersTraceDto(ordersTraceDto);
					orders = generateOrder(userId, goodsExchangeParamDto);
					//获得订单跟踪信息
					CopyUtils.copy(ordersTraceDto, orders);
					orderId = goodsExchangeService.updateGoodsExchangeStatus(orders, goodsExchangeParamDto);
					exchangeStatus = true;
					//返回的结果里包含地址
					replaceChooseAddress(ordersAddressDto);   //需要将省市地址从code转换为名称
					goodsExchangeResponseDto.setOrdersAddressDto(ordersAddressDto);
					//解锁商品待实现
					//日志记录
					SaveGoodsExchangeLogWorker goodsExchangeLogWorker = new SaveGoodsExchangeLogWorker(orders, exchangeStatus);
					singleExecutorTask.executer(goodsExchangeLogWorker);
				} catch (Exception e) {
					//兑换失败,释放库存
					raiseGoodsStock(goodsId);
				}
			}
			
			if (exchangeStatus) {
				//当天购买次数限制
				incrUserCurrentDateBuyingCount(userId, exchangeGoodsConfigDto);
				//商品购买总数限制
				incrUserTotalBuyingCount(userId, exchangeGoodsConfigDto);
				//重置用户积分缓存
				reloadUserCredit(userId);
				//重置用户兑换列表缓存
				reloadUserExchangeList(userId);
				//计算商品销量
				ComputeGoodsSalesWorker computeGoodsSalesWorker = new ComputeGoodsSalesWorker(goodsId);
				singleExecutorTask.executer(computeGoodsSalesWorker);
				CopyUtils.copy(goodsExchangeResponseDto, orders);
				long currTimeMills = DateUtils.currentTimeInMills();
				goodsExchangeResponseDto.setGenerateDate(CustomDateFormatUtils.getyyyyMMddStr(currTimeMills));
				goodsExchangeResponseDto.setId(orderId);
				goodsExchangeResponseDto.setStatus(ExchangeDealStatusConstatns.SUCCESS.getCode());
				
				return goodsExchangeResponseDto;
			}
			if (orders != null)
				CopyUtils.copy(goodsExchangeResponseDto, orders);
			goodsExchangeResponseDto.setStatus(ExchangeDealStatusConstatns.FAILURE.getCode());
			return goodsExchangeResponseDto;
		}
		//库存不足
		raiseGoodsStock(goodsId);
		throw new BusinessException(BusinessConstants.GOODS_STOCK_EMPTY.getCode(), "抢光啦，下次要早点哦~");
	}



	/**
	 * 查询兑换地址
	 * @param addressId ,userId
	 * @return
	 */
	private OrdersAddressDto getAddressDto(Long addressId, long userId) {
		AddressDto addressDto = new AddressDto();
		OrdersAddressDto ordersAddressDto = new OrdersAddressDto();
		if (addressId == null || addressId < 0)
			throw new BusinessException(BusinessConstants.ORDER_ADDRESS_NOT_EXISTS.getCode(), "兑换地址不存在！");
		else if (addressId == 0)				 
			//选用默认地址
			addressDto = addressService.listDefaultAddressByUserId(userId);		
		else									
			//选用传递的地址
			addressDto = addressService.listAddressById(addressId, userId);
		
		if (addressDto == null)
			throw new BusinessException(BusinessConstants.ORDER_ADDRESS_NOT_EXISTS.getCode(), "兑换地址不存在！");
		else {
			CopyUtils.copy(ordersAddressDto, addressDto);
			return ordersAddressDto;
		}
	}

	/**
	 * 查询商品配置
	 * @param goodsId
	 * @return
	 */
	private ExchangeGoodsConfigDto queryExchangeGoodsConfigDtoById(final int goodsId) {
		DataOperation dataOperation = new DataOperation() {
			
			public Object operate() {
				ExchangeGoodsConfigDto exchangeGoodsConfigDto = exchangeGoodsConfigService.queryGoodsConfigDtoById(goodsId);
				return exchangeGoodsConfigDto;
			}
		};
		String goodsConfigKey = GOODS_CONFIG_PREFIX + goodsId;
		List<String> keyList = new ArrayList<>();
		keyList.add(goodsConfigKey);
		CacheParam cacheParam = new CacheParam();
		cacheParam.setKeyList(keyList);
		cacheParam.setPrefix(GOODS_CONFIG_PREFIX);
		RedisManager redisManager = new RedisManager(cacheParam, dataOperation);
		ExchangeGoodsConfigDto exchangeGoodsConfigDto = redisManager.passiveOperateCache(ExchangeGoodsConfigDto.class);
		return exchangeGoodsConfigDto;
	}
	
	//检查是否满足要求
	private void validate(long userId, ExchangeGoodsConfigDto exchangeGoodsConfigDto) {
		//商品是否下架
		long currTimeMills = DateUtils.currentTimeInMills();
		Integer putOnStatus = exchangeGoodsConfigDto.getPutOnStatus();
		Long putOffTime = exchangeGoodsConfigDto.getPutOffTime();
		if (putOnStatus == null)
			throw new BusinessException(BusinessConstants.GOODS_PUT_ON_STATUS_NOT_EXISTS.getCode(), "商品上架状态不存在");
		if (putOffTime == null)
			throw new BusinessException(BusinessConstants.GOODS_PUT_OFF_TIME_NOT_EXISTS.getCode(), "商品下架时间不存在");
		if (putOnStatus != 2 || putOffTime <= currTimeMills)
			throw new BusinessException(BusinessConstants.GOODS_HAD_BEEN_PUT_OFF.getCode(), "商品已下架");
		
		Credit credit = creditService.queryUserCreditByUserId(userId);
		int currentCredit = credit.getCurrentCredit();
		int readyToExpireCredit = credit.getReadyToExpireCredit();
		//定级积分
		int gradeCredit = credit.getLastYearHighestCredit();
		int price = exchangeGoodsConfigDto.getPrice();
		int level = credit.getLevel();
		if (currentCredit < price)
			//用户可用积分不足
			throw new BusinessException(BusinessConstants.CREDIT_NOT_ENOUGH.getCode(), "您的奇遇点不足");
		if (level < exchangeGoodsConfigDto.getExchangeObjectId())
			//兑换等级不足
			throw new BusinessException(BusinessConstants.LEVLE_NOT_ENOUGH.getCode(), "您的会员等级不够哦");
		else {
			if (readyToExpireCredit > 0) {
				List<Integer> vipLevelRangeList = creditGradeProperties.getLevelRange(level);
				int floor = vipLevelRangeList.get(0);
				if (gradeCredit - readyToExpireCredit < floor)
					//当积分失效后被降级
					throw new BusinessException(BusinessConstants.LEVLE_NOT_ENOUGH.getCode(), "您的会员等级不够哦");
			}
		}
		
		//用户当天购买次数
		Integer userCurrentDateBuyingCount = getUserCurrentDateBuyingCount(userId, exchangeGoodsConfigDto);
		//用户总购买次数
		Integer userTotalBuyingCount = getUserTotalBuyingCount(userId, exchangeGoodsConfigDto);
		
		int eachDayExchangeTimeLimit = exchangeGoodsConfigDto.getEachDayExchangeLimit();
		if (eachDayExchangeTimeLimit > 0 && userCurrentDateBuyingCount >= eachDayExchangeTimeLimit)
			throw new BusinessException(BusinessConstants.CURRENT_DAY_BUYING_COUNT_OVER_LIMIT.getCode(), "已超过今日兑换上限啦");
		int eachOneExchangeLimit = exchangeGoodsConfigDto.getEachOneExchangeLimit();
		if (eachOneExchangeLimit > 0 && userTotalBuyingCount >= eachOneExchangeLimit)
			throw new BusinessException(BusinessConstants.TOTAL_BUYING_COUNT_OVER_LIMIT.getCode(), "超出您的可购买上限啦");
	}
	
	//获取用户当天购买次数
	private Integer getUserCurrentDateBuyingCount(final long userId, final ExchangeGoodsConfigDto exchangeGoodsConfigDto) {
		String userCurrentDateBuyingCountKey = CURRENT_DATE_BUYING_COUNT + userId + "_" + exchangeGoodsConfigDto.getId();
		RedisManager redisManager = new RedisManager();
		Integer userCurrentDateBuyingCount = redisManager.getAtomIntegerValue(userCurrentDateBuyingCountKey);
		return userCurrentDateBuyingCount == null ? 0 : userCurrentDateBuyingCount;
	}
	
	//获取用户总购买次数
	private Integer getUserTotalBuyingCount(final long userId, final ExchangeGoodsConfigDto exchangeGoodsConfigDto) {
		String userCurrentDateBuyingCountKey = TOTAL_BUYING_COUNT + userId + "_" + exchangeGoodsConfigDto.getId();
		RedisManager redisManager = new RedisManager();
		Integer userTotalBuyingCount = redisManager.getAtomIntegerValue(userCurrentDateBuyingCountKey);
		return userTotalBuyingCount == null ? 0 : userTotalBuyingCount;
	}
	
	//锁定商品库存
	private int deductGoodsStock(final int goodsId) {
		String goodsStockKey = GOODS_STOCK_PREFIX + goodsId;
		RedisManager redisManager = new RedisManager();
		int stock = redisManager.decr(goodsStockKey);
		return stock;
	}
	
	//释放商品库存
	private int raiseGoodsStock(final int goodsId) {
		String goodsStockKey = GOODS_STOCK_PREFIX + goodsId;
		RedisManager redisManager = new RedisManager();
		int stock = redisManager.incr(goodsStockKey);
		return stock;
	}
	
	//释放兑换码
	private void raiseExchangeCode(final int abstractId, String exchangeCode) {
		String exchangeCodeKey = EXCHANGE_CODE_LIST_PREFIX + abstractId;
		RedisManager redisManager = new RedisManager();
		redisManager.rpush(exchangeCodeKey, exchangeCode);
	}
	
	//获取兑换码
	private String getExchangeCode(final int abstractId) {
		String exchangeCodeKey = EXCHANGE_CODE_LIST_PREFIX + abstractId;
		RedisManager redisManager = new RedisManager();
		String exchangeCode = redisManager.lpop(exchangeCodeKey);
		return exchangeCode;
	}
	
	//增加用户当天购买次数
	private void incrUserCurrentDateBuyingCount(final long userId, final ExchangeGoodsConfigDto exchangeGoodsConfigDto) {
		String userCurrentDateBuyingCountKey = CURRENT_DATE_BUYING_COUNT + userId + "_" + exchangeGoodsConfigDto.getId();
		RedisManager redisManager = new RedisManager();
		Integer limitTimeStamp = exchangeGoodsConfigDto.getEachDayExchangeLimitRefreshTime();
		if (limitTimeStamp > -1) {
			int expireTime = DateUtils.circlePerDaySecondsBetween(limitTimeStamp);
			redisManager.incr(userCurrentDateBuyingCountKey, expireTime);
		}
	}
	
	private Integer computeExpireTime(Long limitTimeStamp) {
		return DateUtils.secondsBetweenFutureTimeMills(limitTimeStamp);
	}
	
	//用户总共购买次数
	private void incrUserTotalBuyingCount(final long userId, final ExchangeGoodsConfigDto exchangeGoodsConfigDto) {
		String userCurrentDateBuyingCountKey = TOTAL_BUYING_COUNT + userId + "_" + exchangeGoodsConfigDto.getId();
		RedisManager redisManager = new RedisManager();
		long putOffTime = exchangeGoodsConfigDto.getPutOffTime();
		int expireTime = computeExpireTime(putOffTime);
		redisManager.incr(userCurrentDateBuyingCountKey, expireTime);
	}
	
	//获取商品id的原子序列号
	private int uniqueNumber(int goodsId) {
		String uniqueNumberKey = GOODS_SERIAL_PREFIX + goodsId;
		RedisManager redisManager = new RedisManager();
		int uniqueNumber = redisManager.incr(uniqueNumberKey);
		return uniqueNumber;
	}
	
	//重置用户积分缓存
	private void reloadUserCredit(final long userId) {
		creditService.reloadUserCredit(userId);
	}

	//重置用户兑换列表缓存
	private void reloadUserExchangeList(long userId) {
		String userExchangeListKey = EXCHANGED_LIST_PREFIX + userId;
		RedisManager redisManager = new RedisManager();
		redisManager.del(userExchangeListKey);		
	}
	
	private CreditHistory generateCreditHistory(long userId, ExchangeGoodsConfigDto exchangeGoodsConfigDto) {
		long currentTimeMills = DateUtils.currentTimeInMills();
		CreditHistory creditHistory = new CreditHistory();
		creditHistory.setChangeOriginStatus(CreditHistoryOriginStants.EXCHANGE.getCode());
		creditHistory.setChangeStatus(CreditHistoryChangeStants.DECR.getCode());
		creditHistory.setCreateTime(currentTimeMills);
		creditHistory.setCredit(exchangeGoodsConfigDto.getPrice());
		creditHistory.setUserId(userId);
		creditHistory.setGenerateDate(CustomDateFormatUtils.getyyyyMMddInt(currentTimeMills));
		String changeOriginDesc = "兑换" + exchangeGoodsConfigDto.getTitle();
		creditHistory.setChangeOriginDesc(changeOriginDesc);
		return creditHistory;
	}
	
	private Orders generateOrder(long userId, GoodsExchangeParamDto goodsExchangeParamDto, int exchangeCodeId) {
		Orders orders = new Orders();
		ExchangeGoodsConfigDto exchangeGoodsConfigDto = goodsExchangeParamDto.getExchangeGoodsConfigDto();
		orders.setCategoryId(exchangeGoodsConfigDto.getCategoryId());
		long currentTime = DateUtils.currentTimeInMills();
		orders.setCreateTime(currentTime);
		orders.setExchangeCodeId(exchangeCodeId);
		orders.setGoodsType(exchangeGoodsConfigDto.getGoodsType());
		orders.setGoodsId(exchangeGoodsConfigDto.getGoodsId());
		orders.setCustomGoodsCode(CustomGoodsConstants.EXCHANGE.getCode());
		orders.setCustomGoodsId(exchangeGoodsConfigDto.getId());
		orders.setGoodsTitle(exchangeGoodsConfigDto.getTitle());
		orders.setStatus(OrdersStatusConstants.GET_GOODS.getCode());
		orders.setPrice(exchangeGoodsConfigDto.getPrice());
		orders.setUserId(userId);
		orders.setGenerateDate(CustomDateFormatUtils.getyyyyMMddInt(currentTime));
		orders.setSerialNumber(computeGoodsSerialNumber(exchangeGoodsConfigDto.getId(), goodsExchangeParamDto.getUniqueNumber(), currentTime));
		return orders;
	}
	
	private Orders generateOrder(long userId, GoodsExchangeParamDto goodsExchangeParamDto) {
		Orders orders = new Orders();
		ExchangeGoodsConfigDto exchangeGoodsConfigDto = goodsExchangeParamDto.getExchangeGoodsConfigDto();
		orders.setCategoryId(exchangeGoodsConfigDto.getCategoryId());
		long currentTime = DateUtils.currentTimeInMills();
		orders.setCreateTime(currentTime);
		orders.setGoodsType(exchangeGoodsConfigDto.getGoodsType());
		orders.setGoodsId(exchangeGoodsConfigDto.getGoodsId());
		orders.setCustomGoodsCode(CustomGoodsConstants.EXCHANGE.getCode());
		orders.setCustomGoodsId(exchangeGoodsConfigDto.getId());
		orders.setGoodsTitle(exchangeGoodsConfigDto.getTitle());
		orders.setStatus(OrdersStatusConstants.GET_GOODS.getCode());
		orders.setPrice(exchangeGoodsConfigDto.getPrice());
		orders.setUserId(userId);
		orders.setGenerateDate(CustomDateFormatUtils.getyyyyMMddInt(currentTime));
		orders.setSerialNumber(computeGoodsSerialNumber(exchangeGoodsConfigDto.getId(), goodsExchangeParamDto.getUniqueNumber(), currentTime));
		return orders;
	}
	
	//计算流水号
	private String computeGoodsSerialNumber(int goodsId, int uniqueNumber, long currentTime) {
		StringBuilder goodsSerialNumber = new StringBuilder();
		String yyyyMMddHHmmssSSSValue = String.valueOf(CustomDateFormatUtils.getyyyyMMddHHmmssSSSLong(currentTime));
		goodsSerialNumber.append(yyyyMMddHHmmssSSSValue);
		String machineNumber = machineConfig.getMachineNumber();
		goodsSerialNumber.append(machineNumber);
		String goodsIdStr = String.valueOf(goodsId);
		int goodsIdLen = goodsIdStr.length();
		if (goodsIdLen < 6) {
			int diff = 6 - goodsIdLen;
			for (int i = 0; i < diff; i++) {
				goodsIdStr = "0" + goodsIdStr;
			}
		}
		goodsSerialNumber.append(goodsIdStr);
		goodsSerialNumber.append(uniqueNumber);
		return goodsSerialNumber.toString();
	}
	
	private void validateUserCurrentCredit(Credit credit, ExchangeGoodsConfigDto exchangeGoodsConfigDto) {
		int price = exchangeGoodsConfigDto.getPrice();
		int currentCredit = deductUserCurrentCredit(credit.getUserId(), price);
		if (currentCredit < 0) {
			addUserCurrentCredit(credit.getUserId(), price);
			//用户可用积分不足
			throw new BusinessException(BusinessConstants.CREDIT_NOT_ENOUGH.getCode(), "您的奇遇点不足");
		}
	}
	
	//尝试扣减用户积分
	private int deductUserCurrentCredit(long userId, int price) {
		String key = USER_CREDIT_PREFIX + userId;
		RedisManager redisManager = new RedisManager();
		Long currentCredit = redisManager.hincrBy(key, "currentCredit", -price);
		return currentCredit.intValue();
	}
	
	//尝试归还用户积分
	private void addUserCurrentCredit(long userId, int price) {
		String key = USER_CREDIT_PREFIX + userId;
		RedisManager redisManager = new RedisManager();
		redisManager.hincrBy(key, "currentCredit", price);
	}
	
	//异步写入商品销量表任务
	class ComputeGoodsSalesWorker implements Runnable {

		private int goodsId;
		
		public ComputeGoodsSalesWorker(int goodsId) {
			this.goodsId = goodsId;
		}

		public void run() {
			GoodsExchangeRecord goodsExchangeRecord = new GoodsExchangeRecord();
			goodsExchangeRecord.setGoodsId(goodsId);
			long currentTime = DateUtils.currentTimeInMills();
			goodsExchangeRecord.setGenerateDate(CustomDateFormatUtils.getyyyyMMddInt(currentTime));
			goodsExchangeRecord.setCreateTime(currentTime);
			goodsExchangeRecordService.insertGoodsExchangeRecord(goodsExchangeRecord);
		}
		
	}
	
	//异步写入兑换日志任务
	class SaveGoodsExchangeLogWorker implements Runnable {
		
		private Orders orders;
		
		private boolean exchangeStatus;
		
		public SaveGoodsExchangeLogWorker(Orders order, boolean exchangeStatus) {
			this.orders = order;
			this.exchangeStatus = exchangeStatus;
		}

		public void run() {
			String goodsExchangeLog = getLogFormat(orders, exchangeStatus);
			goodsExchangeLogger.info(goodsExchangeLog);
		}
		
		private String getLogFormat(Orders order, boolean exchangeStatus) {
/*			String format = "";
			String info = "";
			if (order.getExchangeCodeId() == null) {
				//非兑换码类型
				if (exchangeStatus)
					format = "user_id : %d, succeed exchanged goods, goods_id : %d, goods_title : %s,  "
							+ "exchange_type : %d, price : %d, serial_number : %s, generate_date : %d, create_time : %d";
				else 
					format = "user_id : %d, fail exchanged goods, goods_id : %d, goods_title : %s,  "
							+ "exchange_type : %d, price : %d, serial_number : %s, generate_date : %d, create_time : %d";
				info = String.format(format, order.getUserId(), order.getGoodsId(), order.getGoodsTitle(), order.getGoodsType(),
						order.getPrice(), order.getSerialNumber(), order.getGenerateDate(), order.getCreateTime());
			} else {
				if (exchangeStatus)
					format = "user_id : %d, succeed exchanged goods, goods_id : %d, goods_title : %s,  "
							+ "exchange_code : %d, exchange_type : %d, price : %d, serial_number : %s, generate_date : %d, create_time : %d";
				else
					format = "user_id : %d, fail exchanged goods, goods_id : %d, goods_title : %s,  "
							+ "exchange_code : %d, exchange_type : %d, price : %d, serial_number : %s, generate_date : %d, create_time : %d";
				info = String.format(format, order.getUserId(), order.getGoodsId(), order.getGoodsTitle(), order.getExchangeCodeId(), order.getGoodsType(),
						order.getPrice(), order.getSerialNumber(), order.getGenerateDate(), order.getCreateTime());
			}*/			
			OrdersLogDto ordersLogDto = new OrdersLogDto();
			if(order != null)
				CopyUtils.copy(ordersLogDto, order);
			
			if(exchangeStatus)
				ordersLogDto.setExchangeStatus("succeed exchanged goods");
			else
				ordersLogDto.setExchangeStatus("fail exchanged goods");
			
			return ordersLogDto.toString();
		}
	}
	
	private void replaceChooseAddress(OrdersAddressDto ordersAddressDto) {
		String chooseAddr = ordersAddressDto.getChooseAddr();
		String replaceAddr;
		Map<Integer, String> adminAreaMap = adminAreaProperties.getAdminAreaMap();
		if (chooseAddr != null) {
			String[] addrs = chooseAddr.split("-");
			Integer provinceCode = Integer.parseInt(addrs[0]);
			replaceAddr = adminAreaMap.get(provinceCode);
			
			if (addrs.length > 1) {
				Integer cityCode = Integer.parseInt(addrs[1]);				
				replaceAddr = replaceAddr + "-" + adminAreaMap.get(cityCode);
			}
			ordersAddressDto.setChooseAddr(replaceAddr);
		}
	}
	
}
